'''beta app'''

# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
import re


def write(data=None, filename='out', num=8, index=True, header=True):
    float_format = '%%.%df' % num
    data.to_csv(filename, float_format=float_format,
                index=index, header=header, sep='\t', na_rep='NA',)


class beta():
    ''' beta app'''

    def __init__(self, data=None):

        self.data = pd.DataFrame(data)

    def f3(self, filename_new='f3', num=3):
        float_format = '%%.%df' % num
        self.data.to_csv(filename_new, float_format=float_format, sep='\t')

    def read(self, filepath=None, header=0, index_col=0, test=False, skiprows=None):
        if test == True:
            self.data = pd.read_table(filepath, index_col=index_col, header=header, na_values=[
                                      'NA', 'na', 'null', 'nan', 'NAN', 'NULL', '', ])
            self.data = self.data.T
            self.data.index = self.data.index.size * ['class']
        else:
            self.data = pd.read_table(filepath, index_col=index_col, header=header, na_values=[
                                      'NA', 'na', 'null', 'nan', 'NAN', 'NULL', '', ], skiprows=skiprows)

    def get(self, data=None):
        self.data = pd.DataFrame(data)

    def drop(self, how='any', axis=1):
        self.data = self.data.dropna(axis=axis, how=how)

    def mean(self, method='median'):
        if re.match('mean', method):
            self.data_mean = self.data.groupby(self.data.index).mean()
        else:
            self.data_mean = self.data.groupby(self.data.index).median()

        for i in xrange(self.data_mean.shape[1]):
            row = self.data_mean.iloc[:, i].apply(np.isnan)
            self.data_mean.iloc[row.values,
                                i] = self.data_mean[row.name].mean()

    def max_min(self, ):
        if not hasattr(self, 'data_mean'):
            self.mean()
        # a series, no need to translate
        self.data_mm = self.data_mean.max() - self.data_mean.min()

    def feature_single(self,):
        if not hasattr(self, 'data_mean'):
            self.mean()
        self.data_mm2 = self.data_mean.copy()
        for index in self.data_mean.index:
            # a series
            mean_other = self.data_mean.loc[self.data_mean.index != index, :].median(
            )
            self.data_mm2.loc[index, :] = np.abs(
                self.data_mean.loc[index, :] - mean_other)

    def drop_mean(self, ):
        if not hasattr(self, 'data_mean'):
            self.mean()
        for i in xrange(self.data.shape[0]):
            col = self.data.iloc[i, :].apply(np.isnan)
            self.data.iloc[i,
                           col.values] = self.data_mean.loc[col.name, col.values]

    def to_int(self):
        self.seq = pd.DataFrame(np.zeros(
            self.data.shape), dtype='int', columns=self.data.columns, index=self.data.index)

        # self.seq[(self.data >= 0.) & (self.data < .1)] = 0
        self.seq[(self.data >= .1) & (self.data < .4)] = 1
        self.seq[(self.data >= .4) & (self.data < .6)] = 2
        self.seq[(self.data >= .6) & (self.data < .9)] = 3
        self.seq[(self.data >= .9) & (self.data <= 1.)] = 4

    def to_seq(self):
        self.seq = pd.DataFrame(np.array(['n'] * self.data.size).reshape(
            self.data.shape), columns=self.data.columns, index=self.data.index)

        # self.seq[(self.data >= 0.) & (self.data < .1)] = 0
        self.seq[(self.data >= .1) & (self.data < .4)] = 'a'
        self.seq[(self.data >= .4) & (self.data < .6)] = 'b'
        self.seq[(self.data >= .6) & (self.data < .9)] = 'c'
        self.seq[(self.data >= .9) & (self.data <= 1.)] = 'd'

    def intersect(self, other=None, ax=1):
        if ax == 1:
            index = self.data.columns.intersection(other.data.columns)
            self.data = self.data[index]
        elif ax == 0:
            index = self.data.index.intersection(other.data.index)
            self.data = self.data.loc[index]

    def id_train(self, train=None):
        if not hasattr(train, 'data_mean'):
            train.mean()  # mean in every class
        self.drop()
        self.intersect(train)  # feature contained in train feature
        for id in train.data.columns:
            if id not in self.data.columns:  # test has no a feature in train data
                self.data[id] = train.data_mean[id].mean()
            # self.data.loc[self.data[id].apply(np.isnan), id] = train.data_mean[id].mean() # test feature is np.nan, no use because of self.drop()

    def to_image(self, ):
        pass

    def features(self, feature=None):

        self.feature = pd.read_table(feature, index_col=0)
        self.feature = self.feature.iloc[:, 0].astype('category')

        ps = []
        num_id_use = []
        for ft in self.feature.cat.categories:
            index = self.feature[self.feature == ft].index
            index_use = index.intersection(self.data.columns)
            p = index_use.size / float(index.size)
            ps.append(p)
            num_id_use.append(index_use.size)

        self.feature_use = pd.DataFrame([num_id_use, ps], index=[
                                        'num', 'percent'], columns=self.feature.cat.categories)
        self.feature_use = self.feature_use.T
        self.feature_use = self.feature_use.sort_values(
            'percent', ascending=False)

    def M_val(self,):
        tmp = 1.0 - self.data
        self.M = np.log2(self.data / tmp)

    def b_val(self,):
        tmp = 2**self.data
        self.data = tmp / (1 + tmp)

    def desc(self,):
        self.data_desc = self.data.T.describe()
        self.data_desc = self.data_desc.T.sort_values('mean')
        # self.data_descx = self.data_desc[['min', 'max', 'mean']]

    def balance(self,):
        value_counts = self.data.index.value_counts()
        value_counts_max = value_counts[0]

        dat_clas_overlap_tmp = self.data.loc[value_counts.index[0]]
        for clas in value_counts.index[1:]:
            clas_num = value_counts[clas]
            clas_num_sample = value_counts[0] - clas_num

            dat_clas_tmp = self.data.loc[clas]
            dat_clas_overlap = dat_clas_tmp.sample(
                clas_num_sample, replace=True)
            dat_clas_overlap_tmp = dat_clas_overlap_tmp.append(dat_clas_tmp)
            dat_clas_overlap_tmp = dat_clas_overlap_tmp.append(
                dat_clas_overlap)

        self.data = dat_clas_overlap_tmp
